<?php
/**
 * Created by dt.
 * Info:
 * Date: 2016/9/22
 * Time: 10:01
 */
namespace app\utils;
require_once('qiniu-min-sdk/autoload.php');

use Qiniu\Storage\UploadManager;

class QiniuUtil{

    //java接口相关
    const API_USERNAME = 'yaoping';
    const API_PASSWORD = '123456';
    const API_TOKEN_URL	 ='http://61.130.183.182:8083/apiserver/api/qiNiuUpToken';//测试地址
    const API_FILE_DELETE = 'http://61.130.183.182:8083/apiserver/api/deleteFileByAccount';
    //const API_TOKEN_URL	 ='http://124.160.149.251:8082/apiserver/api/qiNiuUpToken';//正式地址
    //const API_FILE_DELETE = 'http://124.160.149.251:8082/apiserver/api/deleteFileByAccount';

    //单例
    private static $instance = null;

    //七牛token
    private $token = '';
    //七牛UploadManager上传对象
    private $uploadMgr = null;

    //前端上传限制，可配置项，默认为图片上传
    private $optionsKey = array('maxSize', 'allowExt', 'allowMime');
    //文件大小，单位MB
    private $maxSize = 5;
    //文件扩展名
    private $allowExt = array('jpg', 'png', 'gif','jpeg');
    //文件mime属性
    private $allowMime = array('image/jpeg', 'image/png', 'image/gif');
    //临时文件信息
    private $tmp = '';
    //临时文件扩展名
    private $ext = '';

    //用户可见提示，上传失败
    private $errorUploadFail = '文件上传出错，请重试';
    //用户可见提示，上传文件格式不正确
    private $errorTypeFail = '';
    //用户可见提示，上传文件超过限制
    private $errorSizeFail = '';

    /**
     **	单例
     **
     **	@param	array	$options	上传限制配置，默认上传图片，当上传飞图片类文件时需配置$options参数
     **
     **/
    public static function getInstance($options = array()){
        if(empty(self::$instance)){
            self::$instance = new self($options);
        }
        return self::$instance;
    }

    /**
     **	构造函数
     **
     **	@param	array	$options	上传限制配置，默认上传图片，当上传飞图片类文件时需配置$options参数
     **
     **/
    private function __construct($options = array()){
        //配置上传限制选项
        $this->config($options);
        //初始化属性
        $this->token = !empty($this->token) ? $this->token : $this->setToken();
        $this->errorSizeFail = '文件最大不能超过' . $this->maxSize . 'M';
        $this->errorTypeFail = '不支持此格式，请上传' . implode(',', $this->allowExt) . '格式的文件';
    }

    /**
     **	上传限制配置
     **
     **	@param	array	$options	上传限制配置，默认上传图片，当上传飞图片类文件时需配置$options参数
     **
     **/
    public function config($options = array()){
        if(!empty($options)){
            foreach($options as $k => $v){
                if(in_array($k, $this->optionsKey)){
                    $this->$k = $v;
                }
            }
        }
    }

    /**
     **	删除图片
     **
     **/
    public function delete($key){
        $url = self::API_FILE_DELETE . "?username=" . self::API_USERNAME . "&password=" . self::API_PASSWORD . "&key=" . $key;
        $result = json_decode($this->httpGet($url), true);
        if($result['errorcode'] == 0){
            return true;
        }
        return false;
    }

    /**
     **	上传图片到七牛
     **
     **	@param	string	$inputName	input标签name属性
     **	@param	string	$keyName	存储到七牛的key名
     **	@param	bool	$isImg		真实图片检测，当上传为非图片时记得关闭
     **
     **/
    public function upload($inputName, $keyName = '', $isImg = true){
        //java接口检测
        //token是否有效
        if(is_array($this->token)){
            return $this->token;
        }

        //前端检测
        //上传错误检测
        $res = $this->checkUpload($inputName);
        if(is_array($res)){return $res;}
        //后端检测
        //文件大小检测
        $res = $this->checkSize();
        if(is_array($res)){return $res;}
        //文件扩展名检测
        $res = $this->checkExt();
        if(is_array($res)){return $res;}
        //文件mime属性检测
        $res = $this->checkMime();
        if(is_array($res)){return $res;}
        //真实图片检测
        if($isImg){
            $res = $this->checkImg();
            if(is_array($res)){return $res;}
        }
        //客户端上传检测
        $res = $this->checkHttpPost();
        if(is_array($res)){return $res;}

        //所有检测通过，开始上传到七牛
        //初始化七牛UploadManager上传对象
        $this->uploadMgr = new UploadManager();
        //生成key
        $key = !empty($keyName) ? $keyName : $this->generateUniqueKey();
        if(!pathinfo($key, PATHINFO_EXTENSION)){
            $key .= '.' . $this->ext;
        }
        //上传
        $res = $this->uploadMgr->putFile($this->token, $key, $this->tmp['tmp_name'], array('insertOnly' => 0));
        if($res['1'] !== null){	//上传失败
            return $this->generateReturn(9, $this->errorUploadFail, '未知原因');
        }
        return $this->generateReturn(0, '上传成功', array('key' => $key));
    }

    /**
     **	检测是否是客户端上传
     **
     **/
    private function checkHttpPost(){
        if(!is_uploaded_file($this->tmp['tmp_name'])){
            return $this->generateReturn(8, $this->errorUploadFail, '非法的上传途径');
        }
        return true;
    }

    /**
     **	检测是否是真实的图片
     **
     **/
    private function checkImg(){
        if(!@getimagesize($this->tmp['tmp_name'])){
            return $this->generateReturn(7, $this->errorTypeFail, '不是真实的图片');
        }
        return true;
    }

    /**
     **	检测文件类型
     **
     **/
    private function checkMime(){
        if(!in_array($this->tmp['type'], $this->allowMime)){
            return $this->generateReturn(6, $this->errorTypeFail, '不允许的文件Mime类型');
        }
        return true;
    }

    /**
     **	检测文件扩展名
     **
     **/
    private function checkExt(){
        $this->ext = strtolower(pathinfo($this->tmp['name'], PATHINFO_EXTENSION));
        if(!in_array($this->ext, $this->allowExt)){
            return $this->generateReturn(6, $this->errorTypeFail, '不允许的扩展名');
        }
        return true;
    }

    /**
     **	检测文件大小
     **
     **/
    private function checkSize(){
        if($this->tmp['size'] > ($this->maxSize * 1024 * 1024)){
            return $this->generateReturn(5, $this->errorSizeFail, $this->errorSizeFail);
        }
        return true;
    }

    /**
     **	检测前端上传错误
     **
     **/
    private function checkUpload($inputName){
        if(empty($inputName) || empty($_FILES[$inputName])){
            return $this->generateReturn(3, $this->errorUploadFail, '上传控件名错误');
        }
        $this->tmp = $_FILES[$inputName];
        if($this->tmp['error'] != 0){
            $info = $this->errorUploadFail;
            switch($this->tmp['error']){
                case 1:
                    $info = $this->errorSizeFail;
                    $data = '超过了PHP配置文件中upload_max_filesize选项的值';
                    break;
                case 2:
                    $info = $this->errorSizeFail;
                    $data = '超过了表单中MAX_FILE_SIZE选项的值';
                    break;
                case 3:
                    $data = '文件部分被上传';
                    break;
                case 4:
                    $data = '没有选择上传文件';
                    break;
                case 6:
                    $data = '没有找到临时目录';
                    break;
                case 7:
                    $data = '文件不可写';
                    break;
                case 8:
                    $data = '由于PHP的扩展程序中断文件上传';
                    break;
                default:
                    $data = '未知错误';
            }
            return $this->generateReturn(4, $info, $data);
        }
        return true;
    }

    /**
     **	获取七牛token
     **
     **/
    public function getToken(){
        return $this->token;
    }

    /**
     **	通过java接口设置七牛token
     **
     **/
    private function setToken(){
        $url = self::API_TOKEN_URL . '?username=' . self::API_USERNAME . '&password=' . self::API_PASSWORD;
        $result = $this->httpGet($url);
        if(!$result){
            return $this->generateReturn(1, $this->errorUploadFail, '通信错误');
        }
        $result = json_decode($result, true);
        //获取token失败
        if($result['errorcode'] != '0'){
            return $this->generateReturn(2, $this->errorUploadFail, 'token获取失败，' . $result['message']);
        }
        return $result['data'];
    }

    /**
     **	生成唯一键名
     **
     **/
    private function generateUniqueKey(){
        return md5(uniqid(microtime(true),true));
    }

    /**
     **	生成返回数组
     **
     **	@param	int		$status		状态
     **	@param	mix		$info		用户可见信息
     **	@param	mix		$data		返回数据或程序调试信息
     **
     **/
    private function generateReturn($status = 0, $info = '', $data = ''){
        return array(
            'status'	=>	$status,
            'info'		=>	$info,
            'data'		=>	$data
        );
    }

    /**
     **	curl下get通信
     **
     **/
    private function httpGet($url){
        $ch = curl_init();
        //批量配置设置
        curl_setopt_array($ch, array(
            CURLOPT_CONNECTTIMEOUT	=>	30,
            CURLOPT_HEADER			=>	0,
            CURLOPT_RETURNTRANSFER	=>	1,
            CURLOPT_HTTPGET			=>	1,
            CURLOPT_URL				=>	$url
        ));
        $response = curl_exec($ch);
        //通信失败
        if(curl_errno($ch)){
            return false;
        }
        //通信成功，转码为utf-8
        if(json_encode($response) == 'null'){
            $response = iconv('GB2312','UTF-8//IGNORE',$response);
        }
        return $response;
    }

    /**
     **	防止克隆对象
     **
     **/
    private function __clone(){
        //防止clone函数克隆对象，破坏单例模式
    }

    /**
     **	析构函数
     **
     **/
    public function __destruct(){

    }

}

?>